home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / advanced97 / SPECTRAL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  14.1 KB  |  519 lines

  1. /* spectral.c - by Simon Hui, 3Dfx Interactive */
  2.  
  3. /* make a noise texture from multiple frequencies of noise */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <math.h>
  8. #include <GL/glut.h>
  9.  
  10. #if !defined(GL_VERSION_1_1) && !defined(GL_VERSION_1_2)
  11. #define glBindTexture glBindTextureEXT
  12. #endif
  13.  
  14. static int texxsize = 256, texysize = 256;
  15. static int winxsize = 512, winysize = 512;
  16.  
  17. /* the highest and lowest octaves in the final noise */
  18. static int minoctave = 1;
  19. static int maxoctave = 6;
  20.  
  21. static GLenum ifmt = GL_LUMINANCE;
  22.  
  23. /* texture object names */
  24. static GLuint basistex = 1;
  25. static GLuint noisetex = 2;
  26. static GLuint spectraltex = 6;
  27. static GLuint abstex = 7;
  28.  
  29. int
  30. logOf(int n) {
  31.   int i=0;
  32.   for (i=-1; n > 0; i++) {
  33.     n >>= 1;
  34.   }
  35.   return i;
  36. }
  37.  
  38. void
  39. init_texture(void) {
  40.   int i, j, n;
  41.   int w, h;
  42.   unsigned char *basis, *tex;
  43.   
  44.   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  45.   basis = (unsigned char *) malloc(texxsize * texysize);
  46.   w = texxsize / 2;
  47.   h = texysize / 2;
  48.   for (j=0; j < h; j++) {
  49.     for (i=0; i < w; i++) {
  50.       GLint r;
  51.       float u = i / (w - 1.0);
  52.       float v = j / (h - 1.0);
  53.       float f = 3 * u * u - 2 * u * u * u;
  54.       float g = 3 * v * v - 2 * v * v * v;
  55.       
  56.       /* basis is a bicubic spline */
  57.       r = f * g * 0xff;
  58.  
  59.       /* reflect around x and y axes */
  60.       basis[j * texxsize + i] = r;
  61.       basis[j * texxsize + texxsize-i-1] = r;
  62.       basis[(texysize-j-1) * texxsize + i] = r;
  63.       basis[(texysize-j-1) * texxsize + texxsize-i-1] = r;
  64.     }
  65.   }
  66.   glBindTexture(GL_TEXTURE_2D, basistex);
  67.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  68.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  69.   glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texxsize, texysize, 0,
  70.            GL_RED, GL_UNSIGNED_BYTE, basis);
  71.   free(basis);
  72.  
  73.   tex = (unsigned char *) malloc(4 * texxsize * texysize);
  74.   for (n=0; n < 4; n++) {
  75.     for (j=0; j < texysize; j++) {
  76.       for (i=0; i < texxsize; i++) {
  77.     int r = rand();
  78.     
  79.     /* mix it up a little more */
  80.     r = ((r & 0xff) ^ ((r & 0xff00) >> 8)) & 0xff;
  81.  
  82.     /* For simplicity and because some opengl implementations offer    */
  83.     /* more texture color depth for luminance textures than rgb ones,  */
  84.     /* we use a luminance texture for the random noise.  However, you  */
  85.     /* can make the texture rgb instead, and store different random    */
  86.     /* values for r, g, and b; this is especially useful if using      */
  87.     /* noise distortion below, because you'll get different distortion */
  88.     /* values for s and t.                                             */
  89.     tex[j*texxsize + i] = r;
  90.       }
  91.     }
  92.     glBindTexture(GL_TEXTURE_2D, noisetex + n);
  93.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  94.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  95.     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texxsize, texysize, 0,
  96.          GL_RED, GL_UNSIGNED_BYTE, tex);
  97.   }
  98.   free(tex);
  99. }
  100.  
  101. void
  102. init(void) {
  103.   glClearColor(0.0, 0.0, 0.0, 1.0);
  104.   glMatrixMode(GL_PROJECTION);
  105.   glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
  106.   glMatrixMode(GL_MODELVIEW);
  107.   glViewport(0, 0, winxsize, winysize);
  108.   glDisable(GL_DITHER);
  109.   init_texture();
  110. }
  111.  
  112. void
  113. draw_basis(int tsize, int ssize, int xadj, int yadj) {
  114.   float tilessize = 1.0 / ssize;
  115.   float tiletsize = 1.0 / tsize;
  116.   float xoff = (xadj - 0.5) * 0.5 * tilessize;
  117.   float yoff = (yadj - 0.5) * 0.5 * tiletsize;
  118.   float xo, yo;
  119.   int i, j;
  120.  
  121.   glBindTexture(GL_TEXTURE_2D, basistex);
  122.   glMatrixMode(GL_TEXTURE);
  123.   glLoadIdentity();
  124.  
  125.   /* draw as many copies of the basis function as needed for this frequency */
  126.   for (j=0; j < tsize; j++) {
  127.     for (i=0; i < ssize; i++) {
  128.       xo = xoff + i * tilessize;
  129.       yo = yoff + j * tiletsize;
  130.       glBegin(GL_TRIANGLE_STRIP);
  131.       glTexCoord2f(0.f, 0.f); glVertex2f(xo, yo); 
  132.       glTexCoord2f(0.f, 1.f); glVertex2f(xo, yo + tiletsize); 
  133.       glTexCoord2f(1.f, 0.f); glVertex2f(xo + tilessize, yo); 
  134.       glTexCoord2f(1.f, 1.f); glVertex2f(xo + tilessize, yo + tiletsize); 
  135.       glEnd();
  136.     }
  137.   }
  138.   glFinish();
  139. }
  140.  
  141. void
  142. draw_noise_texture(int tsize, int ssize, int xadj, int yadj, int texname) {
  143.   float tilessize = 1.0 / ssize;
  144.   float tiletsize = 1.0 / tsize;
  145.   float xoff = (xadj - 0.5) * 0.5 * tilessize;
  146.   float yoff = (yadj - 0.5) * 0.5 * tiletsize;
  147.   float scale = 1.0 / (texxsize / ssize);
  148.  
  149.   glBindTexture(GL_TEXTURE_2D, texname);
  150.  
  151.   /* scale the texture matrix to get a noise pattern of desired frequency */
  152.   glMatrixMode(GL_TEXTURE);
  153.   glLoadIdentity();
  154.   glScalef(scale,scale,scale);
  155.  
  156.   glBegin(GL_TRIANGLE_STRIP);
  157.   glTexCoord2f(0.f, 0.f); glVertex2f(xoff, yoff); 
  158.   glTexCoord2f(0.f, 1.f); glVertex2f(xoff, yoff + 1.0); 
  159.   glTexCoord2f(1.f, 0.f); glVertex2f(xoff + 1.0, yoff); 
  160.   glTexCoord2f(1.f, 1.f); glVertex2f(xoff + 1.0, yoff + 1.0); 
  161.   glEnd();
  162.   glFlush();
  163. }
  164.  
  165. static float wscale = 0.60;
  166. static unsigned int **octbufs, *spectralbuf, *absbuf;
  167.  
  168. void
  169. make_octaves(void) {
  170.   int w, h, i;
  171.   int octaves = maxoctave - minoctave + 1;
  172.   float weight, sumweight;
  173.  
  174.   glBlendFunc(GL_ZERO, GL_SRC_COLOR);
  175.   glEnable(GL_TEXTURE_2D);
  176.  
  177.   /* find the total weight */
  178.   weight = 1.0;
  179.   sumweight = 0;
  180.   for (i=0; i < octaves; i++) {
  181.     sumweight += weight;
  182.     weight *= wscale;
  183.   }
  184.   octbufs = (unsigned int **) malloc(octaves * sizeof(unsigned int *));
  185.   
  186.   weight = 1.0;
  187.   w = h = (1 << minoctave);
  188.   for (i=0; i < octaves; i++) {
  189.     octbufs[i] = (unsigned int *) malloc(sizeof(unsigned int) * 
  190.                      winxsize * winysize);
  191.     glClear(GL_COLOR_BUFFER_BIT);
  192.     glDisable(GL_BLEND);
  193.     draw_basis(w, h, 0, 0);
  194.     glEnable(GL_BLEND);
  195.     draw_noise_texture(w, h, 0, 0, noisetex);
  196.     glAccum(GL_LOAD, 1.0);
  197.  
  198.     glClear(GL_COLOR_BUFFER_BIT);
  199.     glDisable(GL_BLEND);
  200.     draw_basis(w, h, 1, 0);
  201.     glEnable(GL_BLEND);
  202.     draw_noise_texture(w, h, 1, 0, noisetex + 1);
  203.     glAccum(GL_ACCUM, 1.0);
  204.  
  205.     glClear(GL_COLOR_BUFFER_BIT);
  206.     glDisable(GL_BLEND);
  207.     draw_basis(w, h, 0, 1);
  208.     glEnable(GL_BLEND);
  209.     draw_noise_texture(w, h, 0, 1, noisetex + 2);
  210.     glAccum(GL_ACCUM, 1.0);
  211.  
  212.     glClear(GL_COLOR_BUFFER_BIT);
  213.     glDisable(GL_BLEND);
  214.     draw_basis(w, h, 1, 1);
  215.     glEnable(GL_BLEND);
  216.     draw_noise_texture(w, h, 1, 1, noisetex + 3);
  217.     glAccum(GL_ACCUM, 1.0);
  218.  
  219.     glDisable(GL_BLEND);
  220.     glAccum(GL_RETURN, 1.0);
  221.     glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  222.          octbufs[i]);
  223.     w <<= 1;
  224.     h <<= 1;
  225.   }
  226.   glDisable(GL_TEXTURE_2D);
  227. }
  228.  
  229. static GLboolean need_remake_octaves = GL_TRUE;
  230. static GLboolean need_remake_spectral = GL_TRUE;
  231. static GLboolean need_remake_abs_noise = GL_TRUE;
  232.  
  233. void
  234. make_spectral_noise(void) {
  235.   int i;
  236.   int octaves = maxoctave - minoctave + 1;
  237.   float weight, sumweight;
  238.  
  239.   if (need_remake_octaves) {
  240.     make_octaves();
  241.     need_remake_octaves = GL_FALSE;
  242.   }
  243.   /* find the total weight */
  244.   weight = 1.0;
  245.   sumweight = 0;
  246.   for (i=0; i < octaves; i++) {
  247.     sumweight += weight;
  248.     weight *= wscale;
  249.   }
  250.   glClear(GL_COLOR_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);
  251.   weight = 1.0;
  252.   for (i=0; i < octaves; i++) {
  253.     glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  254.          (GLvoid *) octbufs[i]);
  255.     glAccum(GL_ACCUM, weight/sumweight);
  256.     weight *= wscale;
  257.   }
  258.  
  259.   /* save image in a texture */
  260.   glAccum(GL_RETURN, 1.0);
  261.   spectralbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  262.   glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  263.            spectralbuf);
  264.   glBindTexture(GL_TEXTURE_2D, spectraltex);
  265.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  266.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  267.   glTexImage2D(GL_TEXTURE_2D, 0, ifmt, winxsize, winysize, 0,
  268.            GL_RGBA, GL_UNSIGNED_BYTE, spectralbuf);
  269. }
  270.  
  271. void
  272. make_abs_noise(void) {
  273.   unsigned int *negbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  274.   unsigned int *posbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  275.  
  276.   if (need_remake_spectral) {
  277.     make_spectral_noise();
  278.     need_remake_spectral = GL_FALSE;
  279.   }
  280.   glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  281.            (GLvoid *) spectralbuf);
  282.   glAccum(GL_LOAD, 1.0);
  283.  
  284.   /* make it signed */
  285.   glAccum(GL_ADD, -0.5);
  286.  
  287.   /* get the positive part of the noise */
  288.   glAccum(GL_RETURN, 2.0);
  289.   glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  290.            (GLvoid *) negbuf);
  291.  
  292.   /* invert the negative part of the noise */
  293.   glAccum(GL_RETURN, -2.0);
  294.   glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  295.            (GLvoid *) posbuf);
  296.  
  297.   /* add positive and inverted negative together, and you get abs() */
  298.   glClear(GL_COLOR_BUFFER_BIT);
  299.   glEnable(GL_BLEND);
  300.   glBlendFunc(GL_ONE, GL_ONE);
  301.   glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  302.            (GLvoid *) posbuf);
  303.   glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE, 
  304.            (GLvoid *) negbuf);
  305.  
  306.   /* invert the colors so that peaks are bright instead of dark */
  307.   glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
  308.   glColor4f(1,1,1,1);
  309.   glBegin(GL_TRIANGLE_STRIP);
  310.   glVertex2f(0,0);
  311.   glVertex2f(0,1);
  312.   glVertex2f(1,0);
  313.   glVertex2f(1,1);
  314.   glEnd();
  315.   glDisable(GL_BLEND);
  316.   
  317.   free(posbuf);
  318.   free(negbuf);
  319.  
  320.   /* save image in a texture */
  321.   absbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  322.   glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  323.            (GLvoid *) absbuf);
  324.   glBindTexture(GL_TEXTURE_2D, abstex);
  325.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  326.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  327.   glTexImage2D(GL_TEXTURE_2D, 0, ifmt, winxsize, winysize, 0,
  328.            GL_RGBA, GL_UNSIGNED_BYTE, absbuf);
  329. }
  330.  
  331. static GLboolean show_abs = GL_FALSE;
  332. static GLboolean show_distort = GL_FALSE;
  333. static GLboolean mapcolors = GL_FALSE;
  334. static float distfactor = 0.20;
  335.  
  336. void
  337. display(void) {
  338.   if (need_remake_spectral) {
  339.     make_spectral_noise();
  340.     need_remake_spectral = GL_FALSE;
  341.   }
  342.   if (show_abs) {
  343.     if (need_remake_abs_noise) {
  344.       make_abs_noise();
  345.       need_remake_abs_noise = GL_FALSE;
  346.     }
  347.     glBindTexture(GL_TEXTURE_2D, abstex);
  348.   } else {
  349.     glBindTexture(GL_TEXTURE_2D, spectraltex);
  350.   }
  351.  
  352.   glClear(GL_COLOR_BUFFER_BIT);
  353.   glEnable(GL_TEXTURE_2D);
  354.   glMatrixMode(GL_TEXTURE);
  355.   glLoadIdentity();
  356.  
  357.   if (show_distort) {
  358.     /* Use values in the spectral texture to distort the texture being */
  359.     /* viewed, by jittering the texture coordinates.                   */
  360.  
  361.     float x, y0, y1;
  362.     float s, t0, t1;
  363.     float ds, dt;
  364.     unsigned int pix0, pix1;
  365.     int vrows = 64, vcols = 64;
  366.     int i, j;
  367.  
  368.     for (j=0; j < (vrows - 1); j++) {
  369.       t0 = y0 = j / (vrows - 1.0);
  370.       t1 = y1 = (j + 1) / (vrows - 1.0);
  371.  
  372.       glBegin(GL_TRIANGLE_STRIP);
  373.       for (i=0; i < vcols; i++) {
  374.     s = x = i / (vcols - 1.0);
  375.     pix0 = spectralbuf[j * winxsize + i];
  376.     pix1 = spectralbuf[(j+1) * winxsize + i];
  377.  
  378.     /* Use green component of noise to distort S coord, */
  379.     /* and blue component to distort T coord.  Subtract */
  380.     /* 127.5 to make it signed, and scale by distfactor.*/
  381.  
  382.     ds = ((pix0 & 0x00ff0000) >> 16);
  383.     dt = ((pix0 & 0x0000ff00) >>  8);
  384.     ds = (ds - 127.5) / 127.5 * distfactor;
  385.     dt = (dt - 127.5) / 127.5 * distfactor;
  386.     glTexCoord2f(s + ds, t0 + dt); glVertex2f(x, y0);
  387.     ds = ((pix1 & 0x00ff0000) >> 16);
  388.     dt = ((pix1 & 0x0000ff00) >>  8);
  389.     ds = (ds - 127.5) / 127.5 * distfactor;
  390.     dt = (dt - 127.5) / 127.5 * distfactor;
  391.     glTexCoord2f(s + ds, t1 + dt); glVertex2f(x, y1);
  392.       }
  393.       glEnd();
  394.     }
  395.   } else {
  396.     glBegin(GL_TRIANGLE_STRIP);
  397.     glTexCoord2f(0, 0); glVertex2f(0, 0);
  398.     glTexCoord2f(0, 1); glVertex2f(0, 1);
  399.     glTexCoord2f(1, 0); glVertex2f(1, 0);
  400.     glTexCoord2f(1, 1); glVertex2f(1, 1);
  401.     glEnd();
  402.   }
  403.   glDisable(GL_TEXTURE_2D);
  404.  
  405.   if (mapcolors) {
  406.     /* Map the gray values of the image into colors so that the texture   */
  407.     /* looks like flames.  We do that by defining appropriate splines for */
  408.     /* red, green, and blue.                                              */
  409.  
  410.     float r, g, b;
  411.     float rt = 0.8;
  412.     float gt = 0.3;
  413.     float bt = 0.1;
  414.     int i, j;
  415.     unsigned char *c;
  416.     unsigned int *mapbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  417.       
  418.     glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  419.          mapbuf);
  420.  
  421.     for (j=0; j < winysize; j++) {
  422.       for (i=0; i < winxsize; i++) {
  423.     c = (unsigned char *) &mapbuf[j * winxsize + i];
  424.     r = c[0] / 255.0;
  425.     g = c[1] / 255.0;
  426.     b = c[2] / 255.0;
  427.  
  428.     if (r < (1-rt)) {
  429.       r = 0.0;
  430.     } else {
  431.       float k = (r - (1.0 - rt)) / rt;
  432.       r = (3.0*k*k - 2.0*k*k*k) * 255.0;
  433.     }
  434.     if (g < (1-gt)) {
  435.       g = 0.0;
  436.     } else {
  437.       float k = (g - (1.0 - gt)) / gt;
  438.       g = (3.0*k*k - 2.0*k*k*k) * 255.0;
  439.     }
  440.     if (b < (1-bt)) {
  441.       b = 0.0;
  442.     } else {
  443.       float k = (b - (1.0 - bt)) / bt;
  444.       b = (3.0*k*k - 2.0*k*k*k) * 255.0;
  445.     }
  446.     c[0] = r;
  447.     c[1] = g;
  448.     c[2] = b;
  449.       }
  450.     }
  451.     glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  452.          (GLvoid *) mapbuf);
  453.     free(mapbuf);
  454.   }
  455.   glFlush();
  456. }
  457.  
  458. void
  459. reshape(int w, int h) {
  460.   glViewport(0, 0, w, h);
  461.   glutPostRedisplay();
  462. }
  463.  
  464. enum {
  465.   TOGGLE_ABS, TOGGLE_DISTORT, MORE_DISTORT, LESS_DISTORT, TOGGLE_MAP_COLORS,
  466.   FIRE, QUIT
  467. };
  468.  
  469. void
  470. menu(int value) {
  471.   switch (value) {
  472.   case TOGGLE_ABS:
  473.     show_abs = !show_abs;
  474.     break;
  475.   case TOGGLE_DISTORT:
  476.     show_distort = !show_distort;
  477.     break;
  478.   case MORE_DISTORT:
  479.     if (distfactor > 0.05) distfactor -= 0.05;
  480.     break;
  481.   case LESS_DISTORT:
  482.     if (distfactor < 1.00) distfactor += 0.05;
  483.     break;
  484.   case TOGGLE_MAP_COLORS:
  485.     mapcolors = !mapcolors;
  486.     break;
  487.   case FIRE:
  488.     mapcolors = GL_TRUE;
  489.     show_distort = GL_TRUE;
  490.     show_abs = GL_TRUE;
  491.     break;
  492.   case QUIT:
  493.     exit(0);
  494.   }
  495.   glutPostRedisplay();
  496. }
  497.  
  498. int
  499. main(int argc, char** argv) {
  500.   glutInit(&argc, argv);
  501.   glutInitWindowSize(winxsize, winysize);
  502.   glutInitDisplayMode(GLUT_RGBA | GLUT_ACCUM);
  503.   (void)glutCreateWindow("spectral noise function");
  504.   init();
  505.   glutDisplayFunc(display);
  506.   glutReshapeFunc(reshape);
  507.   glutCreateMenu(menu);
  508.   glutAddMenuEntry("Toggle Absolute Value", TOGGLE_ABS);
  509.   glutAddMenuEntry("Toggle Noise Distortion", TOGGLE_DISTORT);
  510.   glutAddMenuEntry("Decrease Distortion", MORE_DISTORT);
  511.   glutAddMenuEntry("Increase Distortion", LESS_DISTORT);
  512.   glutAddMenuEntry("Toggle Color Mapping", TOGGLE_MAP_COLORS);
  513.   glutAddMenuEntry("Simulation of Fire", FIRE);
  514.   glutAddMenuEntry("Quit", QUIT);
  515.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  516.   glutMainLoop();
  517.   return 0;             /* ANSI C requires main to return int. */
  518. }
  519.